﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Collections;
using Microsoft.WindowsAPICodePack.Taskbar;

namespace CustomControls
{
    delegate void UpdateDelegate();

    public partial class StatusBar : UserControl
    {
        public event EventHandler<BreakpointEventArgs> BreakPointHit;

        #region Properties
        private double _value;
        private Color _bgColor;
        private Color _fgColor;
        List<BreakPoint> _breakPoints;
        public TaskbarManager TbManager { get; set; }
        private BreakPoint _currentBreakPoint;

        /// <summary>
        /// Liefert den aktuellen Breakpoint zurück
        /// </summary>
        [Browsable(false)]
        public BreakPoint CurrentBreakpoint
        {
            get
            {
                return _currentBreakPoint;   
            }
            private set
            {
                _currentBreakPoint = value;
            }
        }

        /// <summary>
        /// Liefert den aktuellen Fortschritt oder legt diesen fest.
        /// </summary>
        [Description("Der Wert für den Fortschritt, muss zwischen 0 und 1 liegen"),
        Category("Verschiedenes")]
        public double Value
        {
            get
            {
                return _value;
            }
            set
            {
                if(value > 1.0)
                {
                    _value = 1.0;
                }
                else if (value < 0.0)
                {
                    _value = 0.0;
                }
                else
                {
                    _value = value;
                }
                update();
            }
        }
        
        /// <summary>
        /// Liefert die Hintergrundfarbe oder legt diese fest.
        /// </summary>
        [Description("Setzt die Hintergrundfarbe für den Fortschrittsbalken"),
        Category("Verschiedenes")]
        public Color BackgroundColor
        {
            get
            {
                return _bgColor;
            }
            set
            {
                _bgColor = value;
            }
        }

        [DefaultValue(false)]
        public bool Error
        { get; set; }

        /// <summary>
        /// Liefert die Hintergrundfarbe oder legt diese fest.
        /// </summary>
        [Description("Setzt die Vordergrundfarbe für den Fortschrittsbalken"),
        Category("Verschiedenes")]
        public Color ForegroundColor
        {
            get
            {
                return _fgColor;
            }
            set
            {
                _fgColor = value;
            }
        }

        public List<BreakPoint> Breakpoints
        {
            get
            {
                return _breakPoints;
            }
        }
        #endregion

        public StatusBar()
        {
            InitializeComponent();
            TbManager = TaskbarManager.Instance;
            TbManager.SetProgressState(TaskbarProgressBarState.NoProgress);
            BackgroundColor = Color.White;
            ForegroundColor = Color.Blue;
            _breakPoints = new List<BreakPoint>();
        }

        public void Add(BreakPoint bp)
        {
            bp.Parent = this;
            _breakPoints.Add(bp);
        }

        public void Remove(BreakPoint bp)
        {
            _breakPoints.Remove(bp);
        }

        public void Remove(int index)
        {
            _breakPoints.RemoveAt(index);
        }

        protected override void OnResize(EventArgs e)
        {
            if ((Breakpoints == null)||(Breakpoints.Count == 0))
                return;
            this.Breakpoints.Last().ProgressPosition = 1 - ((double)this.Breakpoints.Last().Radius / this.Width);
            this.Invalidate(true);
            base.OnResize(e);
        }

        private void update()
        {
            if (InvokeRequired)
            {
                Invoke(new UpdateDelegate(update));
                return;
            }
            TbManager.SetProgressValue((int)(Value * 100), 100);
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.FillRectangle(Error ? new SolidBrush(Color.Red) : new SolidBrush(_bgColor), new Rectangle(0, Height / 3, Width, Height / 3)); //Hintergrundfarbe
            e.Graphics.FillRectangle(new SolidBrush(_fgColor), new Rectangle(0, Height / 3, (int) ((double)Width * Value), Height / 3)); //Vordergrundfarbe

            foreach (BreakPoint itm in _breakPoints)
            {
                itm.Draw();
                if (itm.ProgressPosition == Value)
                {
                    CurrentBreakpoint = itm;
                }
            }
            base.OnPaint(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            foreach (BreakPoint itm in _breakPoints)
            {
                if (e.X > (Width * itm.ProgressPosition) - itm.Radius && e.X < (Width * itm.ProgressPosition) + itm.Radius &&
                    e.Y > (Height / 2.0) - itm.Radius && e.Y < (Height / 2.0) + itm.Radius)
                {
                    //Getroffen
                    Value = itm.ProgressPosition;
                    CurrentBreakpoint = itm;
                    if(BreakPointHit!=null)
                        BreakPointHit(this, new BreakpointEventArgs { BreakPoint = itm });
                }
            }
            base.OnMouseDown(e);
        }
    }

    public class BreakPoint
    {
        #region Properties
        private double _progressPosition;
        private StatusBar _parent;
        private int _radius;
        private Color _innerColor;
        private Color _borderColor;
        private int _borderThickness;
        private String _text;

        /// <summary>
        /// Ruft die Randdicke ab oder legt diese fest.
        /// </summary>
        [Description("Setzt die Randdicke des Breakpoints"),
        Category("Verschiedenes")]
        public int BorderThickness
        {
            get
            {
                return _borderThickness;
            }
            set
            {
                _borderThickness = value;
            }
        }

        /// <summary>
        /// Ruft die innere Farbe des Breakpoints ab oder legt diese fest.
        /// </summary>
        [Description("Setzt die innere Farbe des Breakpoints"),
        Category("Verschiedenes")]
        public Color InnerColor
        {
            get
            {
                return _innerColor;
            }
            set
            {
                _innerColor = value;
            }
        }

        /// <summary>
        /// Ruft die Randfarbe des Breakpoints ab oder legt diese fest.
        /// </summary>
        [Description("Setzt die Randfarbe des Breakpoints"),
        Category("Verschiedenes")]
        public Color BorderColor
        {
            get
            {
                return _borderColor;
            }
            set
            {
                _borderColor = value;
            }
        }

        /// <summary>
        /// Ruft den Radius des Breakpoints ab oder legt diesen fest.
        /// </summary>
        [Description("Setzt den Radius des Breakpoints"),
        Category("Verschiedenes")]
        public int Radius
        {
            get
            {
                return _radius;
            }
            set
            {
                _radius = value;
            }
        }

        /// <summary>
        /// Ruft die Position auf der Progressbar ab oder legt diese fest.
        /// </summary>
        [Description("Setzt die Position auf der Progressbar, muss zwischen 0 und 1 liegen."),
        Category("Verschiedenes")]
        public double ProgressPosition
        {
            get
            {
                return _progressPosition;
            }
            set
            {
                if (value < 0)
                {
                    _progressPosition = 0;
                }
                else if (value > 1)
                {
                    _progressPosition = 1;
                }
                else
                {
                    _progressPosition = value;
                }
            }
        }

        /// <summary>
        /// Setzt das Elternelement, wichtig zum zeichnen
        /// </summary>
        [Browsable(false)]
        public StatusBar Parent
        {
            get
            {
                return _parent;
            }
            set
            {
                _parent = value;
            }
        }

        public String Text
        {
            get
            {
                return _text;
            }
            set
            {
                _text = value;
            }
        }
        #endregion


        public BreakPoint()
        {
            //Standardwerte setzen...
            InnerColor = Color.White;
            BorderColor = Color.LightBlue;
            ProgressPosition = 0.1;
            BorderThickness = 5;
            Radius = 20;
        }

        public void Draw()
        {
            Graphics parentGraphics = Parent.CreateGraphics();
            //Zeichnen des Controls
            parentGraphics.FillEllipse(new SolidBrush(BorderColor), new Rectangle((int)(((double)Parent.Width * ProgressPosition) - Radius), (int)(((double) Parent.Height / 2.0) - Radius),Radius * 2, Radius * 2));
            parentGraphics.FillEllipse(new SolidBrush(InnerColor), new Rectangle((int)(((double)Parent.Width * ProgressPosition) - Radius + BorderThickness), (int)(((double)Parent.Height / 2.0) - Radius + BorderThickness), (Radius * 2) - (BorderThickness * 2), (Radius * 2) - (BorderThickness * 2)));

            SizeF measureString = parentGraphics.MeasureString(Text, new Font("Arial", 10));
            parentGraphics.DrawString(Text, new Font("Arial", 10), Brushes.Black, new PointF((float)((double)(Parent.Width * ProgressPosition) - (measureString.Width / 2.0)), (float)((double)(Parent.Height / 2.0) - measureString.Height / 2.0)));
        }
    }

    public class BreakpointEventArgs : EventArgs
    {
        public BreakPoint BreakPoint { get; set; }
    }
}
